package com.common.utils;

import com.google.gson.Gson;
import com.system.mapper.T_operation_logMapper;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

//import com.alibaba.fastjson.JSONObject;

//@Aspect
//@Configuration//定义一个切面
//申明是个切面
//@Component
//在切入点前的操作，按order的值由小到大执行
//在切入点后的操作，按order的值由大到小执行
//@Order(1)

/**
 * @author dave
 *Pointcut注解中的execution表达式: public * com.demo.*.*(..)
	第一个 public 表示方法的修饰符,可以用*代替
	第一个 * 表示 返回值,*代表所有
	com.demo.* 包路径,.*表示路径下的所有包
	第三个.* 表示路径下,所有包下的所有类的方法
	(..) 表示不限方法参数
	
	注解类,i值是,值越小,优先级越高
	注解方法,分两种情况 
	注解的是 @Before 是i值越小,优先级越高
	注解的是 @After或者@AfterReturning 中,i值越大,优先级越高
	总结两者的概括就是:
	在切入点前的操作，按order的值由小到大执行
	在切入点后的操作，按order的值由大到小执行
	
	@Pointcut 定义一个方法为切点里面的内容为一个表达式,下面详细介绍
	@Before 在切点前执行方法,内容为指定的切点
	@After 在切点后,return前执行,
	@AfterReturning 在切入点,return后执行,如果想对某些方法的返回参数进行处理,可以在这操作
	@Around 环绕切点,在进入切点前,跟切点后执行
	@AfterThrowing 在切点后抛出异常进行处理
	@order(i) 标记切点的优先级,i越小,优先级越高
 */
public class LogAspect {

	private static final Logger log = Logger.getLogger(LogAspect.class);
	@Resource
	private T_operation_logMapper mapper;

	private Gson gson = new Gson();

	private long startTime = System.currentTimeMillis();
	//private long endTime = System.currentTimeMillis();
	// 定义切点Pointcut
	@Pointcut("execution(public * com.*.service..*(..))")
	public void controllerAspect() {
	}

	/*
	@Around("controllerAspect()")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = (HttpServletRequest) sra.getRequest();

		String url = request.getRequestURL().toString();
		String method = request.getMethod();
		String uri = request.getRequestURI();
		String queryString = request.getQueryString();
		Object[] args = pjp.getArgs();
		String params = "";
		Gson gson = new Gson();
		//获取请求参数集合并进行遍历拼接
		if(args.length>0){
			if("POST".equals(method)){
				Object object = args[0];
				Map map = getKeyAndValue(object);
				//params =  JSONObject.toJSON(map).toString();
				params = gson.toJson(map);
				//JSON.toJSONString(map);
			}else if("GET".equals(method)){
				params = queryString;
			}
		}
		log.info("请求开始===地址:"+url);
		log.info("请求开始===类型:"+method);
		log.info("请求开始===参数:"+params);
		// result的值就是被拦截方法的返回值
		Object result = pjp.proceed();
		//String s =  gson.toJson(result);
		log.info("请求结束===返回值:" + gson.toJson(result));
		return result;
	}*/

	//请求method前打印内容
	@Before(value = "controllerAspect()")
	public void methodBefore(JoinPoint joinPoint) {
		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = (HttpServletRequest) requestAttributes.getRequest();

		//打印请求内容
		log.info("------数据日志 methodBefore 开始------");
		log.info("------数据日志 methodBefore 请求地址:" + request.getRequestURL().toString());
		log.info("------数据日志 methodBefore 请求方式:" + request.getMethod());
		log.info("------数据日志 methodBefore 请求类方法:" + joinPoint.getSignature());
		log.info("------数据日志 methodBefore 请求类方法参数:" + Arrays.toString(joinPoint.getArgs()));
		log.info("------数据日志 methodBefore 结束------");
	}

	//在方法执行完结后打印返回内容
	@AfterReturning(returning = "o", pointcut = "controllerAspect()")
	public void methodAfterReturing(Object o) {
		log.info("------数据日志    methodAfterReturing 开始------");
		log.info("------数据日志    methodAfterReturing Response内容:" + gson.toJson(o));
		log.info("------数据日志    methodAfterReturing 请求处理时间为:"+(System.currentTimeMillis() - startTime)/1000 +" （毫秒）");
		log.info("------数据日志    methodAfterReturing 结束------");
	}

	/*
	 * 对象反射取得属性名称及属性值  
	 */
	public static Map<String, Object> getKeyAndValue(Object obj) {
		Map<String, Object> map = new HashMap<>();
		// 得到类对象
		Class userCla = (Class) obj.getClass();
		/* 得到类中的所有属性集合 */
		Field[] fs = userCla.getDeclaredFields();
		for (int i = 0; i < fs.length; i++) {
			Field f = fs[i];
			f.setAccessible(true); // 设置些属性是可以访问的
			Object val = new Object();
			try {
				val = f.get(obj);
				// 得到此属性的值
				map.put(f.getName(), val);// 设置键值
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		return map;
	}

}


